﻿#ifndef DownloadController_H
#define DownloadController_H

#include "HttpDownloader.h"
#include "FtpDownloader.h"
#include <QObject>
#include <QUrl>
#include <QFile>
#include <QThread>
#include <QVector>
#include <QTimer>
#include <QAbstractSocket>
#include <QtNetwork>
#include <thread>
#include <QStorageInfo>
#include <QCryptographicHash>
#include <openssl/sha.h>

//下载控制器，界面只需要和控制器交互
class DownloadController : public QObject
{
    Q_OBJECT
public:
    enum DownloadStatus
    {
        t_Start,                // 起始状态
        t_Downloading,          // 下载中
        t_Pause,                // 暂停
        t_Finished,             // 下载完成
        t_Error                 // 错误
    };
    std::mutex  m_mutex;
    QWaitCondition m_condition;
    std::mutex  fileMutex;

    QNetworkAccessManager *m_Qnam;
    QNetworkReply         *m_Reply;
    //QFile                 *m_File;
    QTimer                *m_pTimer;
    //DownloadController    *m_downloadController;


    //QUrl      m_Url;                // URL地址
    int       m_speed;              // 最高下载速度
   // std::int64_t    m_CurrentRecvBytes;   // 已下载字节数（用于定时器限速）
    std::int64_t    m_HaveDoneBytes;      // 已下载字节数
    std::int64_t  m_nCurrentDownloadSize; //已下载文件大小显示进度
    std::int64_t    m_StartPoint;         // 下载文件的开始字节
    std::int64_t    m_EndPoint;           // 下载文件的结束字节
    QUrl    m_Url;                      //URL地址
    QFile   *m_File;                    //QFile
    QCryptographicHash* expectedHash = new QCryptographicHash(QCryptographicHash::Sha256);
    std::vector<QThread*> m_ThreadList;                 // 每个下载器的线程数组
    std::vector<int> m_ThreadHadDownload;               // 各个下载器线程已下载的字节数

private:
    int redirectIndex=3;                //重定向次数
    QString m_Scheme;                   //协议类型
    std::int8_t   m_DownloadCount;            //分片数量(线程数量）
    std::int8_t   m_FinishedNum;              //已下载完成分片数
    QString m_filePath;                 //本地文件地址

    std::int64_t  m_FileSize;                 //文件大小

    std::string m_outputFile = "C:\\Users\\CHD\\Desktop\\download.txt";

    DownloadStatus m_Status;                            // 当前下载控制器状态

    QTcpSocket *m_tcpSocket;                            // TCP socket，用于FTP查询文件大小
    std::vector<int> delect_num;                        // 存储已经删除的线程Index

    std::vector<HttpDownloader*> m_HttpDownloaderList;  // HTTP线程下载器数组
    std::vector<FtpDownloader*> m_FtpDownloaderList;    // FTP线程下载器数组
public:
    DownloadController(QObject *parent = nullptr);
    ~DownloadController();

    //获取文件大小
    std::int64_t GetFileSize(QUrl url);
     void saveFilesize();
    // 新建下载任务
    void startFileDownload(const QString url, int count, int speed, QString userName, QString password);
    // 暂停下载任务
    void stopFileDownload();
    // 恢复下载任务（程序重启）
    void resumeFileDownload(QString url, int threadNum, int speed, std::vector<int> thExcuteList, QString userName, QString password);
    // 删除下载任务
    void deleteFileDownload();

    // Scheme
    QString getScheme(){return m_Scheme;}
    // URL地址
    void    setURL(const QString& url, const QString& username = NULL, const QString& password = NULL);
    QString getURL(){return m_Url.url();}
    /*
    // 分片数量
    void    setDownloadCount(const qint8& downloadCount){m_DownloadCount = downloadCount;}
    qint8   getDownloadCount(){return m_DownloadCount;}
    */
    // 文件保存地址
    void    setDestPath(const QString fileName);
    std::string getDestPath();
    // 获取当前下载进度
    void getCurrentDownProgress(int& currentSize, int& totalSize){currentSize = m_nCurrentDownloadSize;totalSize = m_FileSize;}
    // 获取当前状态
    DownloadStatus getCurrentStatus(void){return m_Status;}
    //删除已结束的线程索引
    int CountDelectIndex(int m_Index);
    //短链接还原URL
    void shortLink(const QString& url);
    //计算文件哈希值
    std::string calculateFileHash(const std::string& fileName);
    void httpConectSlot(HttpDownloader* tempDownload);
    void ftpConectSlot(FtpDownloader* tempDownload);
    //判断是否连接到网络
    bool isNetWorkOnline();
    //判断磁盘是否已满
    bool isDiskFull(const QString& path,const qint64 DownloadSize);
//信号和槽函数
signals:
    //void FileDownloadFinished();
    void startDownload(QUrl, QFile*);//发给Http/ftp的开始信号
    void stopThreadTask();//发给Http/ftp的停止信号
    void endThreadTask();//发给Http/ftp的结束信号
    void restartThreadTask();//发给Http/ftp的恢复下载信号
    void error(QString error);//发给界面
    void fileDownloadFinished();//发给界面
public slots:
    //界面发过来开始信号
    void onStartTask(QString url, int threadNum, int speed, QString userName, QString password);//界面发过来
    void onStopTask();//界面发过来停止信号
    void onRestartTask(); //界面发过来恢复信号
    void onDeleteTask();//界面发过来

    void onConnected();
    void onError(QString errorMsg);
    void SubPartFinished(int);//每个线程下载完成的处理函数
    void finshedThread();//打印完成线程的Index
    void updateCurrentSize(int,int);//更新每个线程已下载的字节大小
};

#endif // DownloadController_H
